.\" (c) Vadim Goncharov <vadim_nuclight@mail.ru>, 2010.
.\"
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\"    notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\"    notice, this list of conditions and the following disclaimer in the
.\"    documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd October 20, 2010
.Dt SEASRVKQD 8
.Sh NAME
.Nm seasrvkqd
.Nd "server daemon for a SEA Sender protocol"
.Sh SYNOPSIS
.Nm
.Op Fl dqs
.Op Fl p Ar port
.Op Fl c Ar filepath
.Op Fl a Ar addrspec
.Op Fl u Ar url
.Op Fl f Ar number
.Op Fl t Ar seconds
.Op Fl k Ar addr Ns Op Ns / Ns Ar mask
.Op Fl b Ar pattern
.Bk
.Op Ar connclass ...
.Ek
.Sh DESCRIPTION
This is a kqueue-based server daemon for a custom SEA Sender protocol,
see comments at the beginning of source code and/or web pages for more details.
.Pp
The options are as follows:
.Bl -tag -width ".Fl k Ar addr Ns Op /mask"
.It Fl d
Do not fork, enable debug.
Specify this option twice for extra debug info.
.It Fl q
Be quiet to syslog (log fewer info).
Ignored when used with
.Fl d
option.
.It Fl s
Enable stricter protocol format checks.
Kill client on error instead of just warning to logs.
.It Fl p Ar port
Listen on a port
.Ar port
instead of default 8732.
However, this is of limited use, as no clients are currently able
to connect to non-default port.
You may want to use OS redirection tools (e.g.\&
.Nm "ipfw fwd" )
to do such experiments.
.It Fl c Ar filepath
Path to control commands symlink, defaults to
.Pa /var/run/seasrvkq.ctl .
.It Fl a Ar addrspec
Address specification of archiver for server to connect to (that is,
the address where archiver listens for incoming connections).
.Pp
An
.Ar addrspec
could be one of the following:
.Bl -bullet
.It
A positive integer number less than 65536 (that is, 0 isn't allowed).
This is file descriptor (FD) number, and this daemon uses FD number as
a SEA Sender protocol client ID number.
.It
An IPv4 address and port in the usual form
.Sq 1.2.3.4:5678 .
.It
An absolute path to a Unix domain socket, e.g.\& to a
.Pa /var/run/arch.sock . 
.El
.It Fl u Ar url
URL of archiver web page to answer to clients on command #9.
The
.Ar url
defaults to
.Em http://sea.avtf.net/archive/ .
.It Fl f Ar threshold
Flood threshold coefficient determining when client will be killed.
The
.Ar threshold
defaults to 6 and can't be less than 3 (silently reinterpreted as 3 if it is).
.It Fl t Ar seconds
Timeout for temporary bans (both manual and auto) of IP addresses.
Defaults to 
.Ar threshold * max_penalty
seconds.
This timeout can't be less then
.Ar flood_threshold * max_penalty
(6 * 10 by default) seconds.
If it is less, it will be silently raised to this value.
.It Fl k Ar addr Ns Op Ns / Ns Ar mask
Add an IP address (or subnet in CIDR format) to the ban list with
timeout somewhere in year 2038.
May be specified several times.
This option is used to pre-populate ban list, instead of setting
.Fl t
to big value and manually adding addresses via control symlink after start.
.It Fl b Ar pattern
Blacklist a pattern, to be matched in user/computer names.
May be specified several times.
A pattern is a standard
.Xr glob 3
shell pattern with metacharacters
.Dq "*?[]" ,
implemented via
.Xr fnmatch 3 .
Pattern matching is case-insensitive, but this depends on the current
locale of server's process.
.Pp
If name matches a pattern, address is banned for a current ban timeout
.Ns ( Fl t ) .
Patterns in blacklist apply to all addresses and are persistent, though
they can be added or deleted via control symlink.
.Pp
Pattern matching occurs when user logs in or changes name, after names were
sanitized: all control chars (ASCII less than 32) were changed to underscores
.Ns ( Sq "_" )
and angle brackets
.Po
.Sq "<"
and
.Sq ">"
.Pc
were changed to parentheses
.Sq \&(
and
.Sq \&) .
This, however, happens before server unconditionally changes user name
beginning from space (ASCII 32) to underscore (names beginning from
space break userlist sorting in some clients), so that admin may kill
such users if he wish so.
.El
.Pp
After options follows zero or more
.Ar connection class
specifications.
A
.Ar connclass
is defined as:
.Pp
.Sm off
.D1 Ar address Oo / Ar mask Oc : Ar login_timeout : Ar max_conns : Ar max_penalty
.Sm on
.Pp
If
.Ar mask
is not specified, than it is assumed to be 32 (that is, a single IP address).
When server receives a new connection,
.Ar connection class
list is evaluated in
the order specified in the command line, checking client's address against
each entry.
Checking stops at the first match (that is, if you have overlapping subnets,
you must write more specific one first), and parameters described below are
set for client.
If there were no match, then their default values are used.
The parameters are as follows:
.Bl -tag -width "login_timeout"
.It Ar login_timeout
Seconds for newly connected client to issue login command.
If client doesn't login within this interval, the connection is closed.
The lower bound is 1 second, the upper bound is 86400 (1 day).
Default is 30.
.It Ar max_conns
Maximum number of users from one IP address.
Only logged in users are counted to this number.
Just accepted but not yet
logged in connections are subject to
.Ar login_timeout
instead.
The lower bound is 1 connection.
By default this is unlimited (no upper bound).
.It Ar max_penalty
Seconds for flood control algorithm before beginning to throttle client.
See
.Sx FLOOD CONTROL
section for more details.
The default (and lower bound) is 10 seconds.
.El
.Pp
All of these parameters must be within their lower and upper bounds.
If they are less or more than that bounds, they will be silently reinterpreted
as corresponding bound.
.Sh MESSAGE ARCHIVING
Server supports connection to separate archiver process using simple protocol
(see below) to save messages and dump data requested by admin (usually
too big to go to syslog).
Address can be specified as an
.Ar addrspec
described above.
If the
.Ar addrspec
is either ipaddr:port or path to Unix domain socket, daemon initiates
connection to this address, periodically pings it and reconnects if
connection is lost.
If
.Ar addrspec
is a number, it is treated as preopened file descriptor number, in the
latter case on-failure reconnects to archiver are not supported (but
another address could be signalled to daemon, though).
To have a descriptor preopened, daemon could be started from Bourne shells
using redirection e.g.\& like this:
.Pp
.Dl seasrvkqd -a 3 3>&1 | /path/to/archiver.sh
.Pp
Server only writes to archiver socket, not reads, so it is possible for you
to live without separate process - just redirect that stream to file.
The protocol is simple text line-oriented human-readble.
Each command is a text line with case-insensitive first field and integer
second field, number of other space-separated fields depends on command:
.Pp
.Dl cmd bytecount may be other args till end of line\en
.Pp
Then there $bytecount bytes of raw data (often zero), then next line for next
command, and so on.
This can be easily read and parsed by the following shell script:
.Pp
.Bd -literal -offset indent
#!/bin/sh

while read what bytes restofline; do
        msg=`dd bs=1 count=$bytes 2>/dev/null`
        echo what: $what rest of line: $restofline
        echo bytes: "$msg"
done
.Ed
.Pp
This is only a skeleton, of course.
Customize for your needs.
.Bl -diag
.It Note #1:
this protocol is used for other purposes, too, so archiver must
parse command and extract only (public) messages to save, if it wishes.
.It Note #2:
raw data can contain any bytes, e.g. line breaks in \er\en form,
while protocol itself delimits by Unix convention (\en only), be prepared.
.El
Here is the format of message command:
.Pp
.Dl MSG count src_id user_txtIP dst_id unixtime username[machinename]\en
.Pp
Example message from user John at machine FOOBAR (id=4) to all users
(id=0) at 2009-02-13 23:31:30 UTC, then message from user with spaces
in user and machine name, both with CR LF's in message texts:
.Bd -literal -offset indent
MSG 14 4 192.168.0.5 0 1234567890 John[FOOBAR]
Hi!

Test.
MSG 8 5 192.168.0.6 0 1234567904 I am[GOD HERE]
passed
.Ed
.Pp
Other commands can be found in server source code, but they are usually
intuitive enough.
Server also periodically
.Dq pings
archiver with a no-operation
.Em TIME
command, just giving current server Unix time - this may help to diagnose
when archiver connection was lost, for example.
.Sh FLOOD CONTROL
Server also implements primitive IRC-like flood control on clients.
First, if client floods more than allowed
.Ar max_penalty
time (default 10 seconds), it is throttled by reading only one command
every 2 seconds.
If client continues to flood more than
.Ar flood_threshold * max_penalty
seconds (default flood
.Ar threshold
is 6 giving 1 minute), then it is killed and banned for
.Fl t Ar seconds
timeout.
Ban is implemented by resetting connection requests (because SEA clients
always try to reconnect immediately).
These bans are temporary, so you should consider
.Xr tcpdrop 8
and firewall bans for malicious users.
.Pp
The algorithm of flood control is follows:
.Bl -enum
.It
If client's penalty time is in past, it is first set current time.
.It
For every command read from client, penalty time is incremented by one or
more seconds, depending on nature of the command.
.It
If penalty time looks ahead of current time to future by more than
.Ar max_penalty
seconds, then client is throttled by processing each command once per
2 seconds.
.It
As time goes, if clients still floods, penalty time will eventually be
more than
.Ar max_penalty * flood_threshold
seconds ahead of current time.
Then client is killed and banned.
.El
.Pp
In addition to this constant penalty, daemon also have a logarithmic
penalty of the command (message) length, but that is applied only to
long (more than 256 bytes) commands.
The threshold of logarithmic algorithm was chosen for client to be
penalized by 1 second for length < 256 bytes, 2 seconds for 256 to 512,
3 seconds for 512 to 1024, and so on.
.Pp
The goal is to allow the client to be not throttled
in usual small message mode, and throttling threshold should not be
exceeded immediately after the first command - that is, goal is to
allow safe sending e.g.\& one chat message per 2 seconds and one
(small) group message per 10 seconds.
.Sh SIGNALS AND CONTROLLING DAEMON
Server is controlled via a slightly weird way.
There are more commands than accepted signals, and a string argument is
placed into control symlink as it's destination.
When daemon receives signal, it always reads control symlink and will
ignore signal if symlink cannot be read.
This mechanism is similar to FreeBSD's
.Pa /etc/malloc.conf
in that the symlink doesn't point to any real file.
For example, to kill (and ban for current ban timeout) all users with
IP address 1.2.3.4, you do:
.Pp
.Dl ln -s 1.2.3.4 /var/run/seasrvkq.ctl; killall -USR1 seasrvkqd
.Pp
Then daemon is modifying behaviour based on whether symlink
contains positive integer number, IP address, ipaddr:port, IP address/mask
in CIDR format (e.g. 1.2.3.0/24), some keyword or any other
string.
Many commands are equivalent to command-line options.
Currently supported signals are:
.Pp
.Bl -tag -width "SIGWINCH"
.It SIGUSR1
Kill and ban user(s) with specified ID, address or address:port
of it's conection, or matching blacklist pattern or subnet/mask.
Address is always banned for usual timeout,
regardless of whether users from it are currently connected.
Actually, it works the following way:
.Em first
the argument (address, subnet, pattern) is added to banlist or
patterns blacklist, and
.Em then
the entire user list is scanned, checking all users against
new banlist/blacklist, killed if they match.
.It SIGUSR2
Set ban timeout to specified number of seconds
.Ns ( Fl t ) ,
unblacklist pattern,
unban address (or address/mask) or set archiver URL for responses
to clients
.Ns ( Fl u ) .
If keyword is
.Sq debug ,
cycle to next debug
.Ns ( Fl d )
level (0 repeats after 2).
If that is neither number nor address (address/mask), then server checks
if it begins from lower-case substring
.Dq "http://"
(someone may say this is a special case of keyword).
If so, this is an URL for archiver. If not, the exact string is searched
in the patterns blacklist, and removed from there if found.
.It SIGHUP
Set archiver socket path/address to specified ipaddr:port or Unix
domain socket path. Same as
.Fl a ,
except preopened descriptor number
here is not allowed.
Only sets address variable for future use, to
force reconnect send SIGHUP twice with the same
.Ar addrspec .
.It SIGINFO
Print to archiver socket full information about user(s) with
specified ID, address or ipaddr:port of it's connection, or info
about all users if symlink equals to keyword
.Sq all .
If keyword is
.Sq bans ,
then dump current banlist.
Also dump some of the global variables when running in debug mode.
.It SIGWINCH
Takes IP address and sends it in protocol command #13 to all clients
(to make them set secondary server IP address in their configs).
.El
.Pp
This can be shortly summarized in the following table, where
.Dq -
says that combination is not supported (prohibited), and
.Dq *
advices to look above for something non-obvious.
.Pp
.TS
lb lb lb lb lb lb lb
lb l l l l l l.
\&	Number	IP Addr	ip:port	Net/mask	Keywords	Any string
SIGUSR1	ban one	ban all	ban all	ban all	-	-
SIGUSR2	timeout	unban	unban	unban	debug*	URL/unban*
SIGHUP	-	-	archiver*	-	-	archiver*
SIGINFO	dump one	dump all	dump one	-	all,bans	-
SIGWINCH	-	alt srv	-	-	-	-
.TE
.Pp
In FreeBSD, you can obtain both user IP addresses/ports and IDs via
.Xr sockstat 1
command, because daemon uses FD number as user ID.
.Sh FILES
.Bl -tag -width ".Pa /dev/null" -compact
.It Pa /var/run/seasrvkq.ctl
Default value of path to control symlink.
.El
.Sh EXAMPLES
The following is an example of a typical usage
of the
.Nm
command:
.Pp
.Dl "seasrvkqd -sa /var/run/arch.sock -u http://site.ru/archiver/"
.Pp
The following is a hack for the FreeBSD's rc.d-scripts settings
.Pa /etc/rc.conf
in the case you don't need a separate archiver process and need just to
append everything to file:
.Pp
.Dl seasrvkqd_flags="-a 3 3>&1 | daemon sh -c \e"cat >> /tmp/sea.txt\e""
.Pp
The following is an example of banning one IP address and one subnet forever
(though they can be unbanned later via control symlink) and adding two patterns
to blacklist of disallowed names.
Note that second pattern actually searches for two substring in names,
.Dq apple
and
.Dq app1e
(a hacker-style
.Dq l33t
spelling):
.Pp
.Dl "seasrvkqd -k 1.2.3.4 -k 2.3.4.0/24 -b '*fuck*' -b '*app[l1]e*'"
.Pp
The following is the more complicated example of daemon usage:
.Pp
.Dl "seasrvkqd -t 600 109.123.180.100:7:3:180 109.123.180.0/23:7:3:10"
.Pp
Here are the 10-minutes ban timeout and the two connection classes for one
network the server is directly connected to.
Connection to this network is fast, thus
.Ar login_timeout
is set to a small value.
Computers in this network are known to be owned by only one user (no NATs), so
.Ar max_conns
also set to a small value, safe for possible reconnects on errors.
Note that IP 109.123.180.100 is a bot machine, and it is
heavily loaded by users.
So
.Ar max_penalty
is set to 3 minutes, to prevent the bot to be throttled by server when
several users do their requests in parallel.
Otherwise, users may experience delays receiving replies from the bot,
not to mention the bot could be easily banned as
.Dq flooder .
.Sh SEE ALSO
.Xr sockstat 1 ,
.Xr fnmatch 3 ,
.Xr glob 3 ,
.Xr tcpdrop 8
.Pp
.Sy "SEA Sender Protocol Description" ,
.Pa http://code.google.com/p/blastcore/wiki/SEAProtocol
(in Russian).
.Pp
.Sy "Sender And It's History" ,
.Pa http://thesender.ru/
(in Russian).
.Sh HISTORY
Server is written in 2009 for AVTF TPU Hostel as a replacement for 2006's
Java server and VC++ 6.0 SEA Sender client by Alexey Fadeev (#Kpot#) and
Sergey Khilkov (J7).
.Sh AUTHORS
.An Vadim Goncharov Aq vadim_nuclight@mail.ru .
.Sh BUGS
The overall system is ugly and not recommended to use.
See protocol description and history for overview of architectural flaws.
.Pp
Matching of patterns is case-insensitive, but that depends on system library
functions and current locale - and Windows clients typically use different
locale than Unix machines (you may need to tweak daemon process' environment).
